Shiro 可以在任何环境下工作,从简单的命令行程序到大型企业级集群项目,因为环境的多样化,可以通过许多途径来配合当前环境的配置方式进行配置,在本章我们来了解一下 Shiro 核心支持的配置方式。
多种配置选择
Shiro 的 SecurityManager 的实现和其所依赖的组件都是 JavaBean,所以可以用多种形式对 Shiro 进行配置,比如XML(Spring, JBoss, Guice, 等等),YAML, JSON, Groovy Builder markup,及其它,INI 只是 Shiro 一种最基本的配置方式,使得其可以在任何环境中进行配置比如在那些没有以上配置形式的环境中。
Configuration 配置
SecurityManager 创建
创建一个 SecurityManager 并使之可用最简单的方法就是创建一个org.apache.shiro.mgt.DefaultSecurityManager 对象并写将它写入代码,例如:
1 | Realm realm = //实例化或获得一个Realm的实例。我们将稍后讨论Realm。 |
仅仅三行代码,你就可以拥有一个适用于任何程序的功能全面的 Shiro 环境,多么简单。
SecurityManager Object Graph
如同我们在架构简介中讨论过的,Shiro SecurityMangger 本质上是一个由一套安全组件组成的对象模块视图(graph),因为与 JavaBean兼容,所以可以对所有这些组件调用的 getter 和 setter 方法来配置SecurityManager 和它的内部对象视图。
例如,你想用一个自定义的 SessionDAO 来定制 Session Management从而配置一个 SecurityManager 实例,你就可以使用 SessionManager 的 setSessionDAO 方法直接 set 这个 SessionDAO。
1 | ... |
使用这些函数,你可以配置 SecurityManager 视图(graph)中的任何一部分。
虽然在程序中配置很简单,但它并不是我们现实中配置的完美解决方案。在几种情况下这种方法可能并不适合你的程序:
- 它需要你确切知道并实例化一个直接实现(direct implementation),然而更好的做法是你并不需要知道这些实现也不需要知道从哪里找到它们。
- 因为JAVA类型安全的特性,你必须对通过 get 获取的对象进行强制类型转换,这么多强制转换非常的丑陋、累赘并且会和你的类紧耦合。
- SecurityUtils.setSecurityManager 方法会将 SecurityManager 实例化为虚拟机的单独静态实例,在大多数程序中没有问题,但如果有多个使用 Shiro 的程序在同一个 JVM 中运行时,各程序有自己独立的实例会更好些,而不是共同引用一块静态内存。
- 改变配置就需要重新编译你的程序。
然而,尽管有这些不足,在程序中定制的这种方法在限制内存(memory-constrained )的环境中还是很有价值的,像智能电话程序。如果你的程序不是运行在一个限制内存的环境中,你会发现基于文本的配置会更易读易用。
INI Configuration 配置
大多数程序已经改为使用基于文本的配置,不需要依靠代码就可进行修改,对于不熟悉Shiro API的人来说,也易于理解。
创建SecurityManager的两种方式
SecurityManager from an INI resource 从INI资源创建SecurityManager
1 | Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini"); |
SecurityManager from an INI instance 通过INI实例创建SecurityManager
1 | Ini ini = new Ini(); |
现在我们知道如何使用 INI 配置文件创建一个 SecurityManager,让我们仔细了解一下如何定义一个 shiro INI配置文件。
INI Sections
INI 基于文本配置,在独立命名的区域内通过成对的键名/键值组成。键名在每个区域内必须唯一,但在整个配置文件中并不需要这样(这点和JDK的Properties不同),每一个区域(section)可以看作是一个独立的Properties 定义。
注释行可以用“#”或“;”标识。
这里是一个 Shiro 可以理解的各 section 的示例。
1 | [main] |
subject
在 shiro 框架里就是代表着用户,只不过它为了避免与其它包产生命名冲突,才采用了Subject
这个概念。它提供了身份认证,权限检查,登录登出,session等接口,我们在使用 shiro 框架时,只需要和Subject
交互就可以了。
DefaultSecurityManager
作为 shiro 最核心的类,是整个系统的门面类。上面Subject
的所有接口调用,都是转发给它处理的。
当需要确认用户身份时,比如验证用户名和密码。DefaultSecurityManager
会去调用ModularRealmAuthenticator
类的方法,然后ModularRealmAuthenticator
会从Realm
获取用户的身份信息,最后执行身份验证,比如验证密码是否正确。
当需要检查用户是否有权限时,比如判断该用户是否有写权限。DefaultSecurityManager
会去调用ModularRealmAuthorizer
类的方法,然后ModularRealmAuthorizer
会从Realm
获取该用户的权限信息,最后检查用户是否有该权限。
Realm
是 shiro 提出的概念,它表示保存用户信息的地方。当要执行身份验证或权限检查时,都会先去它这里获取信息后,才能对比和检查。我们可以通过自定义Realm
,实现自己的用户管理。
1 | / 获取Subject |
线程安全
从上面的代码可以看到,我们获取Subject
或SecurityManager
都是调用SecurityUtils
的静态方法获取的。之所以 shiro 这样设计,是为了提供线程粒度的隔离。 shrio 允许不同的线程拥有者不同的Subject
和SecurityManager
,这样就能支持多线程。在和 spring web 集成时,每一次请求都会新建一个线程处理。
1 | public abstract class SecurityUtils { |
上面涉及到了ThreadContext
类,顾名思义它保存着只属于当前线程的数据,所以会用到ThreadLocal
类型。下面的代码可以看到它使用了ThreadLocal
类型保存线程属性
1 | public abstract class ThreadContext { |
ThreadContext
存储着两个很重要的属性,Subject
和 SecurityManager
。它单独为这两个属性提供了操作方法
1 | public abstract class ThreadContext { |
参考
1 | https://blog.csdn.net/qq_34021712/article/details/80418112 |
- 本文作者: 初心
- 本文链接: http://funzzz.fun/2021/02/03/Apache Shiro --- 2 配置/
- 版权声明: 本博客所有文章除特别声明外,均采用 MIT 许可协议。转载请注明出处!